/**
 * 
 */
package evolution.tutors;

import java.util.LinkedList;

import evolution.mlp.MLP;

/**
 * @author camille
 * 
 */
public class XOR implements Tutor {

	private final int inputsCount = 2;
	private final int outputsCount = 1;

	private static XOR singleton;

	private final LinkedList<Double> input00;
	private final LinkedList<Double> input01;
	private final LinkedList<Double> input10;
	private final LinkedList<Double> input11;

	private final double outputTrue = 1;
	private final double outputFalse = 0;

	private XOR() {
		input00 = new LinkedList<Double>();
		input00.add(new Double(0));
		input00.add(new Double(0));

		input01 = new LinkedList<Double>();
		input01.add(new Double(0));
		input01.add(new Double(1));

		input10 = new LinkedList<Double>();
		input10.add(new Double(1));
		input10.add(new Double(0));

		input11 = new LinkedList<Double>();
		input11.add(new Double(1));
		input11.add(new Double(1));
	}

	public static XOR getInstance() {
		if (singleton == null) {
			singleton = new XOR();
		}

		return singleton;
	}

	@Override
	public String getName() {
		return "XOR";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see evolution.Tutor#accept(mlp.MLP)
	 */
	@Override
	public boolean accept(MLP mlp) {
		return ((inputsCount == mlp.getInputLayer().size()) && (outputsCount == mlp.getOutputLayer().size()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see evolution.Tutor#fitness(mlp.MLP)
	 */
	@Override
	public double fitness(MLP mlp) {
		double gap = 0;

		try {
			// 00
			mlp.setInputs(input00);
			gap += Math.abs(outputFalse - mlp.getOutputLayer().getFirst().getValue());

			// 01
			mlp.setInputs(input01);
			gap += Math.abs(outputTrue - mlp.getOutputLayer().getFirst().getValue());

			// 10
			mlp.setInputs(input10);
			gap += Math.abs(outputTrue - mlp.getOutputLayer().getFirst().getValue());

			// 11
			mlp.setInputs(input11);
			gap += Math.abs(outputFalse - mlp.getOutputLayer().getFirst().getValue());

			gap /= 4.0;
		} catch (Exception e) {
			e.printStackTrace();
		}

		return gap;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see evolution.Tutor#results(mlp.MLP)
	 */
	@Override
	public String results(MLP mlp) {
		String results = "";

		results += "\t###########################################\n";

		// 00
		try {
			mlp.setInputs(input00);
			results += "\t0 " + getName() + " 0 : " + mlp.getOutputLayer().getFirst().getValue() + "\n";

			// 01
			mlp.setInputs(input01);
			results += "\t0 " + getName() + " 1 : " + mlp.getOutputLayer().getFirst().getValue() + "\n";

			// 10
			mlp.setInputs(input10);
			results += "\t1 " + getName() + " 0 : " + mlp.getOutputLayer().getFirst().getValue() + "\n";

			// 11
			mlp.setInputs(input11);
			results += "\t1 " + getName() + " 1 : " + mlp.getOutputLayer().getFirst().getValue() + "\n";

		} catch (Exception e) {
			e.printStackTrace();
		}

		results += "\t###########################################";

		return results;
	}
}
